Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 35937ec247b1cd8d880f4ae3e3f56037ad511be2


Parents : 81c09d4
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-24T14:33:26-05:00

test(frontend): add unit tests for DownloadUtils and update Utils tests with new formatting functions

Changes

2 files changed, 78 insertions(+), 0 deletions(-)


Diff

diff --git a/tests/frontend/DownloadUtils.test.js b/tests/frontend/DownloadUtils.test.js
new file mode 100644
index 00000000..53d21f65
--- /dev/null
+++ b/tests/frontend/DownloadUtils.test.js
@@ -0,0 +1,28 @@
+import { describe, it, expect, vi, afterEach } from "vitest";
+import DownloadUtils from "@/js/DownloadUtils";
+
+describe("DownloadUtils", () => {
+ afterEach(() => {
+ delete window.MeshChatXAndroid;
+ vi.restoreAllMocks();
+ });
+
+ it("delegates base64 saves to Android bridge when present", () => {
+ const saveDownload = vi.fn();
+ window.MeshChatXAndroid = { saveDownload };
+ DownloadUtils.downloadFromBase64("test.mu", "QUJD");
+ expect(saveDownload).toHaveBeenCalledWith("test.mu", "QUJD");
+ });
+
+ it("downloadFile uses Android bridge when present", async () => {
+ const saveDownload = vi.fn();
+ window.MeshChatXAndroid = { saveDownload };
+ const blob = new Blob([new Uint8Array([1, 2, 3])]);
+ await DownloadUtils.downloadFile("f.bin", blob);
+ expect(saveDownload).toHaveBeenCalledTimes(1);
+ const [name, b64] = saveDownload.mock.calls[0];
+ expect(name).toBe("f.bin");
+ expect(typeof b64).toBe("string");
+ expect(b64.length).toBeGreaterThan(0);
+ });
+});

diff --git a/tests/frontend/Utils.test.js b/tests/frontend/Utils.test.js
index 471cf265..60284ad0 100644
--- a/tests/frontend/Utils.test.js
+++ b/tests/frontend/Utils.test.js
@@ -88,6 +88,56 @@ describe("Utils.js", () => {
});
});
+ describe("formatSecondsWithoutAgo", () => {
+ it("matches formatSeconds without trailing ago", () => {
+ expect(Utils.formatSecondsWithoutAgo(120) + " ago").toBe(Utils.formatSeconds(120));
+ expect(Utils.formatSecondsWithoutAgo(86400) + " ago").toBe(Utils.formatSeconds(86400));
+ });
+ });
+
+ describe("formatTimeAgoForI18n", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it("uses neutral sub-minute phrase for i18n suffixes", () => {
+ const now = new Date("2025-01-01T12:00:00Z");
+ vi.setSystemTime(now);
+ const recent = "2025-01-01 11:59:30";
+ expect(Utils.formatTimeAgoForI18n(recent)).toBe("less than a minute");
+ expect(Utils.formatTimeAgo(recent)).toBe("just now");
+ });
+
+ it("omits ago for minute-scale relative fragments", () => {
+ const now = new Date("2025-01-01T12:00:00Z");
+ vi.setSystemTime(now);
+ const pastDate = "2025-01-01 11:59:00";
+ expect(Utils.formatTimeAgoForI18n(pastDate)).toBe("1 min");
+ expect(Utils.formatTimeAgo(pastDate)).toBe("1 min ago");
+ });
+ });
+
+ describe("formatSecondsAgoForI18n", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it("returns less than a minute for recent unix timestamps", () => {
+ const nowSec = Math.floor(new Date("2025-06-01T15:00:00Z").getTime() / 1000);
+ vi.setSystemTime(new Date("2025-06-01T15:00:00Z"));
+ expect(Utils.formatSecondsAgoForI18n(nowSec - 10)).toBe("less than a minute");
+ expect(Utils.formatSecondsAgoForI18n(nowSec - 120)).toBe("2 mins");
+ });
+ });
+
describe("formatTimeAgo", () => {
beforeEach(() => {
vi.useFakeTimers();


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────